﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;

public class RaceLogic : MonoBehaviour
{
    [DllImport("recast")]
    static extern IntPtr AllocRaceLogic();
    [DllImport("recast")]
    static extern void FreeRaceLogic(IntPtr handle);
    [DllImport("recast")]
    static extern void UpdateRaceLogic(IntPtr handle,long dt);
    [DllImport("recast")]
    static extern bool LoadGeomForRace(IntPtr ptr,byte[] buf, int length);
    [DllImport("recast")]
    static extern bool LoadGeomSettingForRace(IntPtr ptr, byte[] buf, int length);
    [DllImport("recast")]
    static extern bool LoadNavMeshForRace(IntPtr ptr, byte[] buf, int length);
    [DllImport("recast")]
    static extern bool InitCrowd(IntPtr ptr,int maxAgents,long maxAgentRadius);
    [DllImport("recast")]
    static extern int AddAgent(IntPtr ptr, long[] pos);
    [DllImport("recast")]
    static extern void RemoveAgent(IntPtr ptr, int id);
    [DllImport("recast")]
    static extern void GetAgentPos(IntPtr ptr, int id, long[] pos);
    [DllImport("recast")]
    static extern bool SetAgentPos(IntPtr ptr, int id, long[] pos);
    [DllImport("recast")]
    static extern bool AgentMovePos(IntPtr ptr, int id, long[] pos);
    [DllImport("recast")]
    static extern bool AgentMoveVelocity(IntPtr ptr, int id, long[] pos);
    [DllImport("recast")]
    static extern bool StopAgentMove(IntPtr ptr, int id);
    [DllImport("recast")]
    static extern bool AddTempObstacle(IntPtr ptr, int radius, int height, long[] pos, ref int id);
    [DllImport("recast")]
    static extern bool RemoveTempObstacle(IntPtr ptr, ref int id);
    
    [SerializeField]
    TextAsset mesh_asset = null;
    [SerializeField]
    TextAsset geom_setting_asset = null;
    [SerializeField]
    TextAsset nav_mesh_asset = null;

    IntPtr mHandle = IntPtr.Zero;
    bool mInitialized = false;
    private long[] tempPos = new long[3];
    private void Awake()
    {
        UnityEngine.Debug.Log($"<color=#00ff00>RaceLogic Awake</color>");
        if (!InitMesh())
            return;
        UnityEngine.Debug.Log($"<color=#00ff00>初始化网格数据成功</color>");
        if (!InitCrowd(mHandle, 40, 39321))
            return;
        UnityEngine.Debug.Log($"<color=#00ff00>初始化Crowd成功</color>");
        mInitialized = true;
    }

    public IntPtr Handle()
    {
        if (!mInitialized)
            return IntPtr.Zero;
        return mHandle;
    }

    bool InitMesh()
    {
        mHandle = AllocRaceLogic();
        if (IntPtr.Zero == mHandle)
            return false;
        if (null == mesh_asset || null == geom_setting_asset || null == nav_mesh_asset)
            return false;
        if (!LoadGeomForRace(mHandle, mesh_asset.bytes, mesh_asset.bytes.Length))
            return false;
        if (!LoadGeomSettingForRace(mHandle, geom_setting_asset.bytes, geom_setting_asset.bytes.Length))
            return false;
        if (!LoadNavMeshForRace(mHandle, nav_mesh_asset.bytes, nav_mesh_asset.bytes.Length))
            return false;
        return true;
    }

    private void FixedUpdate()
    {
        UpdateRaceLogic(mHandle, ClientNumToRace(Time.fixedDeltaTime));
        // UpdateRaceLogic(mHandle, ClientNumToRace(Time.fixedDeltaTime));
    }

    private void OnDestroy()
    {
        if(mHandle != IntPtr.Zero)
        {
            FreeRaceLogic(mHandle);
            mHandle = IntPtr.Zero;
        }
    }

    public int AddAgent(long x,long y,long z)
    {
        if (mHandle != IntPtr.Zero)
        {
            tempPos[0] = x;
            tempPos[1] = y;
            tempPos[2] = z;
            return AddAgent(mHandle, tempPos);
        }
        return -1;
    }

    public void RemoveAgent(int agentId)
    {
        if (mHandle != IntPtr.Zero)
        {
            RemoveAgent(mHandle, agentId);
        }
    }
    
    public void AgentMoveVelocity(int agentId, long x, long y, long z)
    {
        tempPos[0] = x;
        tempPos[1] = y;
        tempPos[2] = z;
        AgentMoveVelocity(mHandle, agentId, tempPos);
    }

    public void GetAgentPos(int agentId, out long x, out long y, out long z)
    {
        GetAgentPos(mHandle, agentId, tempPos);
        x = tempPos[0];
        y = tempPos[1];
        z = tempPos[2];
    }

    public bool AgentMovePos(int agentId, long x, long y, long z)
    {
        tempPos[0] = x;
        tempPos[1] = y;
        tempPos[2] = z;
        return AgentMovePos(mHandle, agentId, tempPos);
    }

    public bool SetAgentPos(int agentId, long x, long y, long z)
    {
        tempPos[0] = x;
        tempPos[1] = y;
        tempPos[2] = z;
        return SetAgentPos(mHandle, agentId, tempPos);
    }

    public bool StopAgentMove(int agentId)
    {
        return StopAgentMove(mHandle, agentId);
    }
    
    public static void ClientPosToRace(float inX, float inY, float inZ, out long x, out long y, out long z)
    {
        x = (long)(inX * -65536f);
        y = (long)(inY * 65536f);
        z = (long)(inZ * 65536f);
    }

    public static void RacePosToClient(long x, long y, long z, ref Vector3 v)
    {
        v.x = x / -65536f;
        v.y = y / 65536f;
        v.z = z / 65536f;
    }
    
    public static void RacePosToClient(long x, long y, long z, out float xx, out float yy, out float zz)
    {
        xx = x / -65536f;
        yy = y / 65536f;
        zz = z / 65536f;
    }

    public static long ClientNumToRace(float value)
    {
        return (long)(value * 65536f);
    }

}